-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local ipmi = require 'ipmi'
local comp_code = ipmi.types.Cc
local msg = require 'bios.ipmi.ipmi_message'
local log = require 'mc.logging'
local peripherals_device = require 'service.peripherals_device'

local MANUFACTUREID <const> = 0x0007db
local SET_DEVICE_STATUS_KBC_ERROR <const> = 5
local SET_DEVICE_STATUS_VIDEO_ERROR <const> = 3

local KEYBOARD_FAILURE_BIT <const> = 0
local VIDEO_DEVICE_ERROR_BIT <const> = 0

---@description: 带内故障上报处理
local peripherals_ipmi = {}

local function s_unpack(data)
    local val = { string.unpack(string.rep('B', string.len(data)), data) }
    -- string.unpack最后一位会返回其偏移
    return { table.unpack(val, 1, #val - 1) }
end

function get_system_id(ctx)
    if not ctx then
        return 1
    end
    return ctx.HostId or 1
end

-- | BIOS  ->  BMC事件格式      |
-- | Device ID | Device Status1|
-- | 03h       | 00h           |
function peripherals_ipmi.set_device_status_kbc(req, ctx)
    local device_status = s_unpack(req['DeviceStatus'])
    local system_id = get_system_id(ctx)
    log:notice('set_device_status_kbc: system_id %d, EventDir %d, DeviceStatus:' ..
        string.rep(' %d', #device_status), system_id, req['EventDir'], table.unpack(device_status))
    local func = ({
        [KEYBOARD_FAILURE_BIT] = function()
            peripherals_device.get_instance():set_kbc_err(system_id, req['EventDir'] == 0 and 1 or 0)
        end
    })[device_status[1]]
    if not func then -- default
        log:error('invalid device_status(%d)', device_status[1])
        return msg.SetKbcStatusRsp.new(comp_code.UnspecifiedError, req['ManufactureId'])
    end
    func()
    return msg.SetKbcStatusRsp.new(comp_code.Success, req['ManufactureId'])
end

-- | 05h       | 00h           |
function peripherals_ipmi.set_device_status_video(req, ctx)
    local device_status = s_unpack(req['DeviceStatus'])
    local system_id = get_system_id(ctx)
    log:notice('set_device_status_video: system_id %d, EventDir %d, DeviceStatus:' ..
        string.rep(' %d', #device_status), system_id, req['EventDir'], table.unpack(device_status))
    local func = ({
        [VIDEO_DEVICE_ERROR_BIT] = function()
            peripherals_device.get_instance():set_video_err(system_id, req['EventDir'] == 0 and 1 or 0)
        end
    })[device_status[1]]
    if not func then -- default
        log:error('invalid device_status(%d)', device_status[1])
        return msg.SetVedioStatusRsp.new(comp_code.UnspecifiedError, req['ManufactureId'])
    end
    func()
    return msg.SetVedioStatusRsp.new(comp_code.Success, req['ManufactureId'])
end

return peripherals_ipmi